#!/bin/bash
#
# @NAME_SERVICE@
#
# This is the init script for starting up the PostgreSQL server.
#
# This script is slightly unusual in that the name of the daemon (postmaster)
# is not the same as the name of the subsystem (postgresql)
#
# chkconfig: - 64 36
# description: PostgreSQL database server.
# processname: postmaster
# pidfile: /var/run/postmaster.PORT.pid

### BEGIN INIT INFO
# Provides: @NAME_SERVICE@
# Required-Start: $local_fs $remote_fs $network $named $syslog $time
# Required-Stop: $local_fs $remote_fs $network $named $syslog $time
# Short-Description: start and stop PostgreSQL @PGVERSION@ server
# Description: PostgreSQL database server
### END INIT INFO

# PGVERSION is the full package version, e.g., 9.0.2
# Note: the specfile inserts the correct value during package build
PGVERSION=@PGVERSION@

# PGMAJORVERSION is major version, e.g., 9.0 (this should match PG_VERSION)
PGMAJORVERSION=@PGMAJORVERSION@

# PGDOCDIR is the directory containing the package's documentation
# Note: the specfile inserts the correct value during package build

# Distribution README file
README_DIST=@README_DIST@

# Source function library.
. /etc/rc.d/init.d/functions

# Get network config.
. /etc/sysconfig/network

# postgresql-setup library
. "@rawpkgdatadir@/library.sh"

: ${RESTORECON=/sbin/restorecon}
test -x $RESTORECON || RESTORECON=:

@SCL_SOURCE@

# Find the name of the script
NAME=`basename $0`
if [ ${NAME:0:1} = "S" -o ${NAME:0:1} = "K" ]
then
	NAME=${NAME:3}
fi

# Set defaults for configuration variables
PGENGINE=@bindir@

# Only default system service has default PGDATA set.  This allows us to catch
# admin's mistake of not creating /etc/sysconfig/psql/$NAME configuration file
# and just hard/symlinking default init script.  That way we can avoid (inside
# postgresql-check-db-dir) runnnig "secondary" server against "default" data
# directory.
if test "@NAME_SERVICE@" = "$NAME"; then
    PGDATA=@PGDATADIR@
fi

PGLOG=@POSTGRES_HOMEDIR@/pgstartup-@NAME_SERVICE@.log

# Value to set as postmaster process's oom_adj
PG_OOM_ADJ=-17

# Override defaults from /etc/sysconfig/pgsql if file is present
[ -f /etc/sysconfig/pgsql/${NAME} ] && . /etc/sysconfig/pgsql/${NAME}

export PGDATA
export PGPORT
export PGSTARTTIMEOUT
export PGSCLS

lockfile="/var/lock/subsys/${NAME}"

# Ideally, we should use $PGDATA/postmaster.pid.  It apparently works, but to
# be honest I'm not sure about consequences.  Most probably 'service status'
# would not work for non-root/non-postgres users.  TODO?
pidfile="/var/run/${NAME}.pid"

script_result=0

# admin_cmd CMD [ARGS [...]]
# --------------------------
admin_cmd ()
{
    local space="" arg="" cmd="" log="$ADMIN_PGLOG"
    for arg; do
        cmd+="$space$(printf %q "$arg")"
        space=' '
    done

    local cmd="( umask 0077; @SCL_SOURCE@; $cmd )"

    test -n "$log" || log=/dev/null
    cmd+=" >>$(printf %q "$log")"
    cmd+=" 2>>$(printf %q "$log")"

    debug "running command under postgres user: $cmd"
    @SU_POSTGRES@ -c "$cmd" < /dev/null
}

start()
{
	[ -x "$PGENGINE/postgres" ] || exit 5

	PSQL_START=$"Starting ${NAME} service: "

	# Make sure startup-time log file is valid
	if [ ! -e "$PGLOG" -a ! -h "$PGLOG" ]
	then
        admin_cmd touch "$PGLOG" || exit 4
        admin_cmd $RESTORECON "$PGLOG"
	fi

    admin_cmd \
        "PGDATA=$PGDATA" \
        @libexecdir@/postgresql-check-db-dir "$NAME" || {
        echo_failure
        echo
        exit 1
    }

	echo -n "$PSQL_START"
	test x"$PG_OOM_ADJ" != x && echo "$PG_OOM_ADJ" > /proc/self/oom_adj

    # Note that this does not fail/exit the 'service start' if the postmaster
    # is already running.  We should probably 'status' first and start only if
    # postmaster is down.  This just unnecessarily wastes time and generates
    # too much (false) rush in $PGLOG.
    #
    # The maximum waiting time PGSTARTTIMEOUT is set to 30 second to not hold
    # the system too long.  See `man pg_ctl & -w option`.  This is not issue in
    # case of systemd.
    #
    # PGSTARTWAIT turns on waiting for server to become fully ready to accept
    # connection.

    # clean the variable if not set to 1
    test x1 != x"$PGSTARTWAIT" && PGSTARTWAIT=

    # success if already started (pg_ctl -w could fail later)
    status -p "$pidfile" postgres &>/dev/null && {
        success "$PSQL_START"
        echo
        exit 0
    }

    ADMIN_PGLOG="$PGLOG" admin_cmd \
            "PGSCLS=$PGSCLS" \
            "PGOPTS=$PGOPTS" \
            "PGPORT=$PGPORT" \
            @libexecdir@/postgresql-ctl start -D "$PGDATA" \
            -s ${PGSTARTWAIT:+-w -t ${PGSTARTTIMEOUT:-30}}

    if test $? -ne 0; then
        failure "$PSQL_START"
        echo
        script_result=1
        return
    fi

    # pg_ctl succeed, now recognize the pid number

    pid=
    if test x1 != x"$PGSTARTWAIT" ; then
        # We don't wait for the full postgresql server start.  In this case,
        # wait for pidfile creation only.  This should take _very_ short time in
        # most cases but on highly overloaded machines - several seconds may
        # not be enough.  See rhbz#800534 and rhbz#1188942 for more info.
        # Original waiting implementation by Jozef Mlích.

        decounter=${PGSTARTTIMEOUT:-30}
        while test "$decounter" -ge 0; do
            pid=$(head -n 1 "$PGDATA/postmaster.pid" 2>/dev/null)

            test "x$pid" != x && break

            # pidfile does not exist yet, wait a sec more
            decounter=$(( decounter - 1 ))
            sleep 1
        done
    else
        # pg_ctl -w succeed, pidfile must exist if everything is OK
        pid=$(head -n 1 "$PGDATA/postmaster.pid" 2>/dev/null)
    fi

    if test "x$pid" != x; then
        success "$PSQL_START"
        touch "$lockfile"
        echo "$pid" > "$pidfile"
        echo
    else
        failure "$PSQL_START"
        echo
        script_result=1
    fi
}

stop()
{
	echo -n $"Stopping ${NAME} service: "
	if [ -e "$lockfile" ]
	then
        admin_cmd "$PGENGINE/pg_ctl" stop -D "$PGDATA" -s -m fast
	    ret=$?
	    if [ $ret -eq 0 ]
	    then
		echo_success
		rm -f "$pidfile"
		rm -f "$lockfile"
	    else
		echo_failure
		script_result=1
	    fi
	else
	    # not running; per LSB standards this is "ok"
	    echo_success
	fi
	echo
}

restart(){
    stop
    start
}

condrestart(){
    [ -e "$lockfile" ] && restart || :
}

reload()
{
    admin_cmd "$PGENGINE/pg_ctl" reload -D "$PGDATA" -s
}

__single_comand()
{
    local msg="$1"
    shift
    echo $"$msg ($@)"
    "$@" && success || failure || script_result=1
    echo
}


initdb()
{
    __single_comand $"Initializing database" \
        @bindir@/@NAME_BINARYBASE@-setup --initdb --unit "$NAME" "$@"
}


upgrade()
{
    __single_comand $"Upgrading database" \
        @bindir@/@NAME_BINARYBASE@-setup --upgrade --unit "$NAME" "$@"
}


# See how we were called.
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  status)
	status -p "$pidfile" postgres
	script_result=$?
	;;
  restart)
	restart
	;;
  condrestart|try-restart)
	condrestart
	;;
  reload)
	reload
	;;
  force-reload)
	restart
	;;
  initdb)
    shift
    initdb "$@"
    ;;
  upgrade)
    shift
    upgrade "$@"
    ;;
  *)
	echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|initdb|upgrade}"
	exit 2
esac

exit $script_result
